package cn.itsource.basic.service.impl;

import cn.itsource.basic.dto.PhoneRegisterDto;
import cn.itsource.basic.eum.PhoneRegisterCons;
import cn.itsource.basic.service.VerifyCodeService;
import cn.itsource.basic.util.BusinessException;
import cn.itsource.basic.util.SmsUtil;
import cn.itsource.basic.util.StrUtils;
import cn.itsource.basic.util.VerifyCodeUtils;
import cn.itsource.user.domain.Logininfo;
import cn.itsource.user.domain.User;
import cn.itsource.user.mapper.LogininfoMapper;
import cn.itsource.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;




    /**
     * 获取图形验证码
     *
     * @param imageCodeKey
     * @return
     */
    @Override
    public String imageCode(String imageCodeKey) throws IOException {
        // 1.生成验证码
        String codeStr = VerifyCodeUtils.generateVerifyCode(1);
        // 2.存到redis
        redisTemplate.opsForValue().set(imageCodeKey, codeStr, 3, TimeUnit.MINUTES);
        // 3.返回base64编码的
        return VerifyCodeUtils.VerifyCode(80, 30, codeStr);
    }

    /**
     * 发送短信验吗
     *
     * @param dto
     */
    @Override
    public void smsCode(PhoneRegisterDto dto) {
        if (("binder").equals(dto.getType())){
            // 发送短信验证码
            this.sendSmsCode(dto,PhoneRegisterCons.BINDER_CODE_KEY);
        }else if ("register".equals(dto.getImageCodeKey())){
            //发送图形验证码
            this.verifyImageCode(dto);
            // 验证图形验证码
            this.sendSmsCode(dto,PhoneRegisterCons.PHONE_CODE_KEY);
        }
    }

    private void sendSmsCode(PhoneRegisterDto dto, String binderCodeKey) {
        // 4.判断手机号验证码两次发送时间是否大于60秒
        Long  timeout =  redisTemplate.getExpire(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getPhone()));
        if (timeout > (PhoneRegisterCons.PHONE_CODE_TIME - 1*60L)){
            // 就是一分钟内访问了两次
            throw new BusinessException("别点！");
        }
        // 5.是否需要重新生成手机号验证码
        // 基于我们目前reids中有手机号验证码 如果有 我们就发送老的 没有我们就生成一个新的
        String redisPhoneCode = (String) redisTemplate.opsForValue().get(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getPhone()));
        if (StringUtils.isBlank(redisPhoneCode)){
            // 如果没有 我们就生成一个
            redisPhoneCode = StrUtils.getRandomString(4);
        }
        log.info("手机验证码：{}",redisPhoneCode);
        // 6.将手机号验证码存到redis
        redisTemplate.opsForValue().set(String.format(PhoneRegisterCons.PHONE_CODE_KEY, dto.getPhone()),redisPhoneCode,
                PhoneRegisterCons.PHONE_CODE_TIME,TimeUnit.SECONDS);
        // 7.发送短信
//        SmsUtil.send();
    }

    private void verifyImageCode(PhoneRegisterDto dto) {
        // 1.参数验证
        //2.图形验证码是否正确
        // 从redis中获取到图形验证码 然后和dto中的图形验证码进行比较
        String redisImageCode = (String) redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (StringUtils.isBlank(redisImageCode) || !redisImageCode.equalsIgnoreCase(dto.getImageCodeValue())) {
            throw new BusinessException("图形验证码错误！");
        }
        // 3.手机号是否注册过
        // 根据dto中的手机号查询user表中是否有数据
        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user) {
            throw new BusinessException("滚去登陆！");
        }
    }

    /**
     * 手机号注册接口
     * @param dto
     */
    @Override
    public void phoneRegister(PhoneRegisterDto dto) {
        // 参数校验
        // 验证两次密码是否一致
        if (!dto.getPassword().equals(dto.getPasswordRepeat())){
            throw new BusinessException("两次密码不一致！");
        }
        // 验证手机号验证码是否正确
       String redisPhoneCode = (String) redisTemplate.opsForValue().get(String.format(PhoneRegisterCons.PHONE_CODE_KEY,dto.getPhone()));
        if (StringUtils.isBlank(redisPhoneCode) || !redisPhoneCode.equals(dto.getPhoneCode())){
            throw new BusinessException("手机验证码错误！");
        }
        // 验证手机号是否注册过
        User user = userMapper.findByPhone(dto.getPhone());
        if (null != user) {
            throw new BusinessException("滚去登陆！");
        }
        // 保存数据 先 logininfo 再user
        user = dto.getUser();
        // 构建logininfo对象
        Logininfo logininfo = new Logininfo();
        // 这个api 会将user对象中的字段值 复制到logininfo中 前提是两个实体字段相同
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setDisable(true);
        logininfo.setType(1);
        // 添加logininfo表
        logininfoMapper.add(logininfo);
        // 在添加user表 将logininfoid set到user表中
        user.setLogininfoId(logininfo.getId());
        userMapper.add(user);
    }
}
